#pragma once
#include <memory>
#include <mutex>
#include <iostream>
using std::cout;
using std::endl;
namespace chy
{
	template<class T>
	class auto_ptr 
	{
	public:
		auto_ptr(T* ptr=nullptr)
			:_ptr(ptr)
		{}
		auto_ptr(auto_ptr<T>& sp)
			:_ptr(sp._ptr)
		{
			sp._ptr = nullptr;
		}
		auto_ptr<T>& operator=(auto_ptr<T>& sp)
		{
			if (this != &sp)
			{
				if (_ptr)
				{
					cout << "释放原来的空间成功" << endl;
					delete _ptr;
				}
				_ptr = sp._ptr;
				sp._ptr = nullptr;
			}
			return *this;
		}
		~auto_ptr()
		{
			if (_ptr) 
			{
				cout << "Delete: " <<_ptr<< endl;
				delete _ptr;
			}
		}
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}

	private:
		T* _ptr;
	};

	template<class T>
	class unique_ptr
	{
	public:
		unique_ptr(T* sp=nullptr)
			:_ptr(sp)
		{}
		unique_ptr(const unique_ptr<T>& up) = delete;
		unique_ptr<T>& operator=(const unique_ptr<T>& up) = delete;
		~unique_ptr()
		{
			if (_ptr)
			{
				cout << "Delete: " << _ptr << endl;
				delete _ptr;
			}
		}
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}

	private:
		T* _ptr;
	};

	template<class T>
	class shared_ptr
	{
	public:
		shared_ptr(T* sp=nullptr)
			:_ptr(sp)
			,_pCount(new int(1))
			,_pmtx(new std::mutex)
		{}

		shared_ptr(const shared_ptr<T>& sp)
			:_ptr(sp._ptr)
			,_pCount(sp._pCount)
			,_pmtx(sp._pmtx)
		{
			AddCount();
		}
		shared_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			if (this == &sp) return *this;
			Release();
			_ptr = sp._ptr;
			_pCount = sp._pCount;
			_pmtx = sp._pmtx;
			AddCount();
			return *this;
		}
		void AddCount()
		{
			_pmtx->lock();
			++(*_pCount);
			_pmtx->unlock();
		}
		void Release()
		{
			_pmtx->lock();
			bool flag = false;

			if (--(*_pCount) == 0 && _ptr)
			{
				cout << "Delete: " << _ptr << endl;
				delete _ptr;
				delete _pCount;
				flag = true;
			}
			_pmtx->unlock();
			if (flag) delete _pmtx;
			
		}
		~shared_ptr()
		{
			Release();
		}

		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
		//这个接口是给weak_ptr准备的 用来拿到指针
		T* get() const
		{
			return _ptr;
		}
	private:
		T* _ptr;
		int* _pCount = 0;
		std::mutex* _pmtx;
	};

	//weak_ptr是搭配shared_ptr使用的 单独没有用
	template<class T>
	class weak_ptr
	{
	public:
		weak_ptr()
			:_ptr(nullptr)
		{}
		weak_ptr(const shared_ptr<T>& sp)
			:_ptr(sp.get())
		{}
		weak_ptr(const weak_ptr<T>& wp)
			:_ptr(wp._ptr)
		{}
		weak_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			_ptr = sp.get();
			return *this;
		}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}


	private:
		T* _ptr;
	};


	template<class T>
	struct DeleteArray
	{
		void operator()(T* ptr)
		{
			cout << "delete[]" << ptr << endl;
			delete[] ptr;
		}
	};

	template<class T>
	struct Free
	{
		void operator()(T* ptr)
		{
			cout << "free" << ptr << endl;
			free(ptr);
		}
	};

}
class A
{
public:
	~A()
	{
		cout << "~A()" << endl;
	}
	//private:
	int _a1 = 0;
	int _a2 = 0;
};

struct Node
{
	int _val;
	chy::weak_ptr<Node> _next;
	chy::weak_ptr<Node> _prev;

	~Node()
	{
		cout << "~Node" << endl;
	}
};
